package com.example.tutorial.java.concurrent.limit;

import java.time.LocalTime;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 固定窗口(计数器)
 * 思路：通过一个支持原子操作的计数器来累计1s内的请求数，当1s内达到限流阈值时触发拒绝策略。每过1s计数器重置为0重新计数。
 * 问题：在时间窗口临界突变条件下不能限制住请求数(第1秒的后500ms和第2秒的前500ms)
 *
 * @author: cph
 * @date: 2022/8/16 11:28
 */
public class RateLimiterFixedWindow {

    private static Integer QPS = 2;
    private static long TIME_WINDOW = 1000L;
    private static AtomicInteger REQ_COUNT = new AtomicInteger();
    private static long START_TIME = System.currentTimeMillis();

    public synchronized static boolean tryAcquire() {
        if ((System.currentTimeMillis() - START_TIME) > TIME_WINDOW) {
            REQ_COUNT.set(0);
            START_TIME = System.currentTimeMillis();
        }
        return REQ_COUNT.incrementAndGet() <= QPS;
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            LocalTime now = LocalTime.now();
            Thread.sleep(250);
            if (tryAcquire()) {
                System.out.println(now + " 通过");
            } else {
                System.out.println(now + " 限流");
            }
        }
    }

}
